﻿/*
 * fbasync - An Asynchronous Facebook API for .NET
 * Copyright (C) 2007 ittybittysoft
 * Email: info@ittybittysoft.com
 * Portions of the library are based on the Facebook Developer Toolkit
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
using System;
using System.Threading;
using System.Diagnostics;

namespace fbasync
{
    public class LazyAsyncResult<T>
        : IAsyncResult
        where T : class, new()
    {
        private T _myAsyncState;
        private object _asyncState;
        private volatile bool _isCompleted = false;
        private volatile bool _completedSynchronously = false;
        private object _syncroot = new object();
        private Exception _asyncException = null;
        private readonly AsyncCallback _callback;
        private LazyInit<ManualResetEvent> _waitEvent = new LazyInit<ManualResetEvent>(
                delegate { return new ManualResetEvent(false); });

        public LazyAsyncResult()
        {
            _myAsyncState = new T();
            _callback = null;
        }

        public LazyAsyncResult(AsyncCallback callback)
        {
            _callback = callback;
            _myAsyncState = new T();
        }

        public LazyAsyncResult(AsyncCallback callback, object asyncState)
        {
            _callback = callback;
            _myAsyncState = new T();
            _asyncState = asyncState;
        }

        public LazyAsyncResult(T myAsyncState, AsyncCallback callback)
        {
            _myAsyncState = myAsyncState;
            _callback = callback;
        }

        public LazyAsyncResult(T myAsyncState, AsyncCallback callback, object asyncState)
        {
            _myAsyncState = myAsyncState;
            _callback = callback;
            _asyncState = asyncState;
        }

        public Exception AsyncException
        {
            get { return _asyncException; }
            protected set { _asyncException = value; }
        }

        public object AsyncState
        {
            get { return _asyncState; }
        }

        public T MyAsyncState
        {
            get { return _myAsyncState; }
            protected internal set { _myAsyncState = value; }
        }

        public System.Threading.WaitHandle AsyncWaitHandle
        {
            get { return _waitEvent.Value; }
        }

        public bool CompletedSynchronously
        {
            get { return _completedSynchronously; }
            protected set { _completedSynchronously = value; }
        }

        public bool IsCompleted
        {
            get { return _isCompleted; }
        }

        public virtual void SetComplete(Exception ex)
        {
            SetComplete(ex, false);
        }

        public virtual void SetComplete(Exception ex, bool completedSynchronously)
        {
            if (null != ex)
                Log.WriteWarning(ex, "Asynchronous Exception: ");

            _asyncException = ex;
            SetComplete(completedSynchronously);
        }

        public virtual void SetComplete(bool completedSynchronously)
        {
            lock (_syncroot)
            {
                if (_isCompleted == true)
                    throw new InvalidOperationException("AsyncResult is already complete");

                _isCompleted = true;

                _completedSynchronously = completedSynchronously;
            }

            _waitEvent.Value.Set();
            if (null != _callback)
                _callback(this);
        }

        public virtual void SetComplete()
        {
            SetComplete(false);
        }

        object IAsyncResult.AsyncState
        {
            get { return _asyncState; }
        }

        WaitHandle IAsyncResult.AsyncWaitHandle
        {
            get { return AsyncWaitHandle; }
        }

        bool IAsyncResult.CompletedSynchronously
        {
            get { return CompletedSynchronously; }
        }

        bool IAsyncResult.IsCompleted
        {
            get { return IsCompleted; }
        }
    }
}
